import java.io.File;
import java.io.FileOutputStream;
import java.util.Arrays;

/*
 * Top 10 Random Mean Absolute Difference
 */
public class AWTopAD extends Scheduler implements Runnable {
	int start;
	int stop;
	byte[] BLOCK;
	int[] markVoteId;
	byte[] markVote;

	final static int N = 150;

	final double NONE = Double.NaN;

	public AWTopAD(int start, int stop) {
		this.start = start;
		this.stop = stop;
	}

	void writeBlock() {
		String FILE_NAME = String.format("%s%07d.bin", BLOCK_PATH, start);
		markVoteId = null;
		markVote = null;
		File out = new File(FILE_NAME);
		FileOutputStream fos;
		try {
			fos = new FileOutputStream(out);
			fos.write(BLOCK);
		} catch (Exception e) {
			e.printStackTrace();
		}

		System.out.println("Done writing: " + FILE_NAME + " @ "
				+ this.getClass());
	}

	@Override
	public void run() {
		markVoteId = new int[USERA.length];
		markVote = new byte[USERA.length];
		int ilen = USERB[0].ilen;
		BLOCK = new byte[(stop - start) * ilen];

		int c = 0;
		for (int bUserId = start; bUserId < stop; bUserId++) {
			for (int i = 0; i < ilen; i++) {
				int bItemId = USERB[bUserId].items[i];
				byte pred = predict(bUserId, bItemId);
				BLOCK[c * ilen + i] = pred;
			}
			c++;
		}
		writeBlock();
	}

	byte predict(int bUserId, int bItemId) {
		int[] items = USERA[bUserId].items;
		int ilen = USERA[bUserId].ilen;
		int n = ilen;
		int top = n / 10;
		if (n > N) {
			top = N/10;
		}
		SimVotePair[] svp = new SimVotePair[n];
		for (int s = 0; s < n; s++) {
			svp[s] = new SimVotePair(0, USERA[bUserId].mean);
		}		
		Item bItem = ITEMA[bItemId];
		for (int userI = 0; userI < bItem.ulen; userI++) {
			markVoteId[bItem.users[userI]] = bItemId;
			markVote[bItem.users[userI]] = bItem.votes[userI];
		}
		for (int i = 0; i < ilen; i++) {
			double similarity = 100 - Math.abs(absDiffFast(bItemId, items[i]));
			if (similarity > svp[i].similarity) {
				svp[i].similarity = similarity;
				svp[i].vote = USERA[bUserId].votes[i];
			}
		}
		Arrays.sort(svp);
		double mean = 0;
		double div = 0;
		for (int i = 0; i < top; i++) {
			double weight = svp[i].similarity/100;
			mean += svp[i].vote*weight;
			div += weight;
		}
		mean /= div;
		return (byte) mean;
	}

	double absDiffFast(int iID, int jID) {
		double diff = 0;
		double n = 0;
		Item j = ITEMA[jID];
		for (int userJ = 0; userJ < j.ulen; userJ++) {
			if (markVoteId[j.users[userJ]] == iID) {
				diff += Math.abs(markVote[j.users[userJ]]
						- j.votes[userJ]);
				n++;
			}
		}
		if (n != 0) {
			return diff / n;
		}
		return Double.MAX_VALUE;
	}
}
